import { log } from "node:console"
import { ApiMsgEnum, EntityTypeEnum, IClientInput, IMsgClientSync, InputTypeEnum, IState, toFixed } from "../Common"
import { Connection } from "../Core"
import { Player } from "./Player"
import { PlayerManager } from "./PlayerManager"
import { RoomManager } from "./RoomManager"
/**
 * @param id:房间id
 * @param Players:房间内的玩家
 */
export class Room{
    id:number
    players :Set<Player>=new Set()
    //收集所有玩家的输入，等待服务器统一处理
    pendingInput:IClientInput[]=[]
    lastTime:number
    lastPlayerFrameIdMap:Map<number,number>=new Map()
    timers: NodeJS.Timer[] = [];

    constructor(rid:number){
        this.id = rid
    }
    //房间内同步
    sync(){
        for (const player of this.players) {
            player.connection.sendMsg(ApiMsgEnum.MsgRoom,{
                room:RoomManager.Instance.getRoomView(this),
            })
        }
    }
    //加入房间方法
    join(uid:number){
        const player= PlayerManager.Instance.idMapPlayer.get(uid)
        if(player){
            player.rid=this.id
            this.players.add(player)
        }
    }
    //离开房间方法
    leave(uid:number){
        const player= PlayerManager.Instance.idMapPlayer.get(uid)
        if(player){
            player.rid = -1;
            player.connection.unlistenMsg(ApiMsgEnum.MsgClientSync, this.getClientMsg, this);
            this.players.delete(player)
            if(!this.players.size){
                RoomManager.Instance.closeRoom(this.id)
            }
        }
    }
    //关闭房间房间
    close(){
        this.timers.forEach(timer=>clearInterval(timer))
        for (const player of this.players) {
            player.rid=-1
            player.connection.sendMsg(ApiMsgEnum.MsgGameEnd,{})
            player.connection.unlistenMsg(ApiMsgEnum.MsgClientSync,this.getClientMsg,this)
        }
        this.players.clear()
    }
    //开始游戏方法，发送state给客户端，渲染角色
    start(){
         //描述场景实体的状态
        const state:IState ={
             //场景里的角色数组
            actors:[...this.players].map((player,index)=>({             
                id:player.id,
                nickname:player.nickname,      
                type: index === 0 ? EntityTypeEnum.Actor1 : EntityTypeEnum.Actor2, //角色类型
                weaponType: index === 0 ? EntityTypeEnum.Weapon1 : EntityTypeEnum.Weapon2,    //武器类型
                bulletType: index === 0 ? EntityTypeEnum.Bullet1 : EntityTypeEnum.Bullet2,    //子弹类型
                hp:100,
                position:{
                x:-150+index*300,
                y:-150+index*300,
                
                },
                direction:{
                x:1,
                y:0,
                },
                
            })), 
            //场景里的子弹数组
            bullets:[],
            nextBulletId:1,
            seed:1,
        }

        for (const player of this.players) {
            //返回消息给每个客户端
            player.connection.sendMsg(ApiMsgEnum.MsgGameStart,{
                state,
            })
            //在游戏开始时监听玩家输入
            player.connection.listenMsg(ApiMsgEnum.MsgClientSync,this.getClientMsg,this)
        }
        /**
         * 每100毫秒向每个玩家发送服务器同步消息（帧同步）
         */
        const timer1 = setInterval(() => {
            this.sendServerMsg()
        }, 100);
        //每16ms执行一次timepast
        const timer2 = setInterval(() => {
            this.timePast()
        }, 16);
    }
    /**
     * 将客户端的输入数据添加到待处理输入数组
     * @param connection 
     * @param param1 
     */
    getClientMsg(connection:Connection,{input,frameId}:IMsgClientSync){
        this.pendingInput.push(input)
        //记录客户端传入的最新frameId，用于预测回滚
        this.lastPlayerFrameIdMap.set(connection.playerId, frameId)
    }
    /**
     * 向每个玩家发送服务器同步消息
     */
    sendServerMsg(){
        const inputs = this.pendingInput 
        this.pendingInput = []
        for (const player of this.players) {
            //返回消息给每个客户端
            player.connection.sendMsg(ApiMsgEnum.MsgServerSync,{
                lastFrameId: this.lastPlayerFrameIdMap.get(player.id) ?? 0,
                inputs,
            })
        }
    }


    timePast(){
        //这个方法可以拿到当前进程的运行时间
        const now = process.uptime()
        const dt = now - (this.lastTime??now)
        this.pendingInput.push({
                type:InputTypeEnum.TimePast,
                //两次时间流逝的时间差
                dt:toFixed(dt),
                
            })
        this.lastTime =now
        // DataManager.Instance.applyInput({
        //     type:InputTypeEnum.TimePast,
        //     //两次时间流逝的时间差
        //     dt,
        // })  
    }
    
}